//
//  RTNavigationController.m
//  AutobotsPlugin
//
//  Created by 张志恒 on 16/11/7.
//  Copyright © 2016年 Autohome. All rights reserved.
//

#import "RTNavigationController.h"
#import <objc/runtime.h>

static const CGFloat kAnimationDuration = 0.25;

@interface RTNavigationController () <UIGestureRecognizerDelegate>

@property (nonatomic, strong) UIView *backgroundView;

@end

@implementation RTNavigationController

#pragma mark - life cycle
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationBarHidden = YES;
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.enabled = NO;
    }
    
    UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] init];
    popRecognizer.delegate = self;
    popRecognizer.maximumNumberOfTouches = 1;
    [self.view addGestureRecognizer:popRecognizer];
    [popRecognizer addTarget:self action:@selector(handlePopGesture:)];
}

#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
    /**
     *  这里有4个条件不允许手势执行：
     *  1、当前控制器为根控制器；
     *  2、interactivePopDisabled属性为NO；
     *  3、大于返回手势允许响应的最大距离；
     *  4、如果系统push、pop动画正在执行（私有属性）；
     */
    
    // Ignore when no view controller is pushed into the navigation stack.
    if (self.viewControllers.count <= 1) {
        return NO;
    }
    
    // Ignore when the active view controller doesn't allow interactive pop.
    UIViewController *topViewController = self.viewControllers.lastObject;
    if (topViewController.rt_interactivePopDisabled) {
        return NO;
    }
    
    // Ignore when the beginning location is beyond max allowed initial distance to left edge.
    CGPoint beginningLocation = [gestureRecognizer locationInView:gestureRecognizer.view];
    CGFloat maxAllowedInitialDistance = topViewController.rt_interactivePopMaxAllowedInitialDistanceToLeftEdge;
    if (maxAllowedInitialDistance > 0 && beginningLocation.x > maxAllowedInitialDistance) {
        return NO;
    }
    
    // Ignore pan gesture when the navigation controller is currently in transition.
    if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
        return NO;
    }
    
    // Prevent calling the handler when the gesture begins in an opposite direction.
    CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
    if (translation.x <= 0) {
        return NO;
    }
    
    return YES;
}

#pragma mark - private methods
- (UIViewController *)lastViewController
{
    return (UIViewController *)self.viewControllers.lastObject;
}

- (void)moveViewWithProgress:(CGFloat)progress {
    CGFloat width = self.view.frame.size.width;
    
    self.view.transform = CGAffineTransformMakeTranslation(width*progress, 0);
    self.backgroundView.transform = CGAffineTransformMakeTranslation(width/3*progress, 0);
}

- (void)gestureRecognizerStateCompleted
{
    [UIView animateWithDuration:kAnimationDuration
                     animations:^{
                         [self moveViewWithProgress:1];
                     } completion:^(BOOL finished) {
                         
                         // 导航栏控制器的视图复位
                         [self.backgroundView removeFromSuperview];
                         self.view.transform = CGAffineTransformIdentity;
                         self.view.layer.shadowPath = nil;
                         
                         
                         if ([self lastViewController].rt_popGestureEndBlock) {
                             [self lastViewController].rt_popGestureEndBlock(YES);
                         }
                         
                         [self popViewControllerAnimated:NO];
                     }];
}

- (void)gestureRecognizerStateFailed
{
    [UIView animateWithDuration:kAnimationDuration
                     animations:^{
                         [self moveViewWithProgress:0];
                     } completion:^(BOOL finished) {
                         if ([self lastViewController].rt_popGestureEndBlock) {
                             [self lastViewController].rt_popGestureEndBlock(NO);
                         }
                     }];
}

#pragma mark - event responses
- (void)handlePopGesture:(UIPanGestureRecognizer *)recognizer
{
    /**
     *  我们用手指在视图中的位置与视图宽度比例作为它的进度。
     */
    CGFloat progress = [recognizer translationInView:recognizer.view].x / recognizer.view.bounds.size.width;
    /**
     *  稳定进度区间，让它在0.0（未完成）～1.0（已完成）之间
     */
    progress = MIN(1.0, MAX(0.0, progress));
    
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
        {
            self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
            self.view.layer.shadowColor = [UIColor lightGrayColor].CGColor;
            self.view.layer.shadowOffset = CGSizeMake(-3, 0);
            self.view.layer.shadowRadius = 5;
            self.view.layer.shadowOpacity = 0.8;
            
            
            [self.view.superview insertSubview:self.backgroundView belowSubview:self.view];
            self.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[[self.viewControllers[self.viewControllers.count-2] view] rt_snapshot]];
            
            
            if ([self lastViewController].rt_popGestureBeginBlock) {
                [self lastViewController].rt_popGestureBeginBlock();
            }
        }
            break;
        case UIGestureRecognizerStateChanged:
        {
            [self moveViewWithProgress:progress];
            
            if ([self lastViewController].rt_popGestureInProgress) {
                [self lastViewController].rt_popGestureInProgress(progress);
            }
        }
            break;
        case UIGestureRecognizerStateEnded:
        {
            if (progress >= 0.5) {
                [self gestureRecognizerStateCompleted];
            } else {
                [self gestureRecognizerStateFailed];
            }
        }
            break;
        case UIGestureRecognizerStateFailed:
        case UIGestureRecognizerStateCancelled:
        {
            [self gestureRecognizerStateFailed];
        }
            break;
        default:
            break;
    }
}

#pragma mark - setters and getters
- (UIView *)backgroundView {
    if (!_backgroundView) {
        _backgroundView = [[UIView alloc] initWithFrame:CGRectOffset(self.view.bounds, -self.view.bounds.size.width/3, 0)];
        _backgroundView.backgroundColor = [UIColor blackColor];
    }
    return _backgroundView;
}

@end

@implementation UIViewController (RTFullscreenPopGesture)

- (BOOL)rt_interactivePopDisabled
{
    return [objc_getAssociatedObject(self, @selector(rt_interactivePopDisabled)) boolValue];
}

- (void)setRt_interactivePopDisabled:(BOOL)rt_interactivePopDisabled
{
    objc_setAssociatedObject(self, @selector(rt_interactivePopDisabled), @(rt_interactivePopDisabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (CGFloat)rt_interactivePopMaxAllowedInitialDistanceToLeftEdge
{
#if CGFLOAT_IS_DOUBLE
    return [objc_getAssociatedObject(self, @selector(rt_interactivePopMaxAllowedInitialDistanceToLeftEdge)) doubleValue];
#else
    return [objc_getAssociatedObject(self, @selector(rt_interactivePopMaxAllowedInitialDistanceToLeftEdge)) floatValue];
#endif
}

- (void)setRt_interactivePopMaxAllowedInitialDistanceToLeftEdge:(CGFloat)rt_interactivePopMaxAllowedInitialDistanceToLeftEdge
{
    objc_setAssociatedObject(self, @selector(rt_interactivePopMaxAllowedInitialDistanceToLeftEdge), @(MAX(0, rt_interactivePopMaxAllowedInitialDistanceToLeftEdge)), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (RTNavigationPopGestureDidBegin)rt_popGestureBeginBlock
{
    return objc_getAssociatedObject(self, @selector(rt_popGestureBeginBlock));
}


- (void)setRt_popGestureBeginBlock:(RTNavigationPopGestureDidBegin)rt_popGestureBeginBlock
{
    objc_setAssociatedObject(self, @selector(rt_popGestureBeginBlock), rt_popGestureBeginBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (RTNavigationPopGestureInProgress)rt_popGestureInProgress
{
    return objc_getAssociatedObject(self, @selector(rt_popGestureInProgress));
}

- (void)setRt_popGestureInProgress:(RTNavigationPopGestureInProgress)rt_popGestureInProgress
{
    objc_setAssociatedObject(self, @selector(rt_popGestureInProgress), rt_popGestureInProgress, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (RTNavigationPopGestureDidEnd)rt_popGestureEndBlock
{
    return objc_getAssociatedObject(self, @selector(rt_popGestureEndBlock));
}

- (void)setRt_popGestureEndBlock:(RTNavigationPopGestureDidEnd)rt_popGestureEndBlock
{
    objc_setAssociatedObject(self, @selector(rt_popGestureEndBlock), rt_popGestureEndBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end

@implementation UIView (RTSnapshot)

- (UIImage *)rt_snapshot
{
    UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, 0);
    if ([self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
        [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    } else {
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    }
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}

@end
